package com.alibaba.shop.provider.third;

import com.alibaba.fastjson.JSON;
import org.apache.http.HttpHost;
import org.elasticsearch.action.bulk.BulkRequest;
import org.elasticsearch.action.bulk.BulkResponse;
import org.elasticsearch.action.delete.DeleteRequest;
import org.elasticsearch.action.delete.DeleteResponse;
import org.elasticsearch.action.get.GetRequest;
import org.elasticsearch.action.get.GetResponse;
import org.elasticsearch.action.index.IndexRequest;
import org.elasticsearch.action.index.IndexResponse;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestClient;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.common.unit.DistanceUnit;
import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.index.query.GeoDistanceQueryBuilder;
import org.elasticsearch.index.query.MatchAllQueryBuilder;
import org.elasticsearch.index.query.QueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.sort.GeoDistanceSortBuilder;
import org.elasticsearch.search.sort.SortBuilder;
import org.elasticsearch.search.sort.SortOrder;

import java.io.IOException;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

/**
 * 基于es原生客户端，实现工具类封装*/
public class TransportUtil {
    //客户端对象
    private static RestHighLevelClient client;
    static {
       client=new RestHighLevelClient(RestClient.builder(
               new HttpHost("192.168.1.5",9200)));
    }
    /**
     * 新增 or 修改*/
    public static String addOrUpdate(String indexName,String id,String json){
        try {
            IndexResponse response = client.index(new IndexRequest(indexName).id(id).
                    source(json, XContentType.JSON), RequestOptions.DEFAULT);
            return response.status().name();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }
    /**
     * 删除
     *
     */
    public static String del(String indexName,String id){
        try {
            DeleteResponse response = client.delete(new DeleteRequest(indexName,id), RequestOptions.DEFAULT);
            return response.status().name();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 查询
     * @param indexName
     * @param id
     * @return
     */
    public static String get(String indexName,String id){
        try {
            GetResponse response = client.get(new GetRequest(indexName,id), RequestOptions.DEFAULT);
            return response.getSourceAsString();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }
    /**
     * 批量新增*/
    public static <T> String batchAdd(String indexName, List<T> list){
        //1.实例化批处理请求对象
        BulkRequest request=new BulkRequest();
        //2.循环遍历，需要添加数据
        for(T t:list){
            //3.创建新增请求对象，并添加
            request.add(new IndexRequest(indexName).id(getId(t)).source(JSON.toJSONString(t),XContentType.JSON));
        }

        try {
            //4.执行批处理，并获取响应结果
            BulkResponse responses=client.bulk(request,RequestOptions.DEFAULT);
            //5.返回操作状态结果
            return responses.status().name();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }
    /**
     * 获取类中id属性的值*/
    private static <T> String getId(T obj){
        Field field= null;
        try {
            field = obj.getClass().getDeclaredField("id");
            field.setAccessible(true);
            return field.get(obj).toString();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return "";
    }

    /**
     * 查询全部
     * @param indexName
     * @param clz
     * @param <T>
     * @return
     */
    public static <T> List<T> queryAll(String indexName,Class<T> clz){
        try {
            //1.执行搜索请求并获取搜索结果
            SearchResponse response=client.search(initRequest(indexName,QueryBuilders.matchAllQuery(),null),RequestOptions.DEFAULT);
            //2.返回结果
            return getResult(response,clz);
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }
    /**
     * 实例化搜索请求对象
     */
    private static SearchRequest initRequest(String indexName, QueryBuilder builder, SortBuilder sort){
        //1.实例化资源搜索对象
        SearchSourceBuilder sourceBuilder=new SearchSourceBuilder();
        //2.添加搜索条件并设置分页等相关信息
        sourceBuilder.query(builder);
        if(sort!=null) {
            sourceBuilder.sort(sort);
        }else {
            sourceBuilder.sort("id",SortOrder.ASC);
        }
        //3.创建搜索请求对象
        SearchRequest request=new SearchRequest(indexName);
        request.source(sourceBuilder);
        return request;
    }
    /**
     * 结果处理
     **/
    private static List<String> getResult(SearchResponse response){
        //1.获取搜索的结果对象
        SearchHits hits=response.getHits();
        List<String> list=new ArrayList<>();
        //2.jdk8 函数式编程 变量数组，并解析为对象
        Arrays.stream(hits.getHits()).forEach(s->{
            list.add(s.getSourceAsString());
        });
        return list;
    }
    /**
     * 结果处理*/
    private static <T> List<T> getResult(SearchResponse response,Class<T> clz){
        //1.获取搜索的结果对象
        SearchHits hits=response.getHits();
        List<T> list=new ArrayList<>();
        //2.jdk8 函数式编程 变量数组，并解析为对象
        Arrays.stream(hits.getHits()).forEach(s->{
            list.add(JSON.parseObject(s.getSourceAsString(),clz));
        });
        return list;
    }
    /**
     * 实现geo排序*/
    private static GeoDistanceSortBuilder getGeoSort(double lat,double lon){
        //2.实例化geo排序对象
        GeoDistanceSortBuilder sortBuilder=new GeoDistanceSortBuilder("location",lat,lon);
        //3.设置排序信息
        sortBuilder.unit(DistanceUnit.METERS);//距离的单位，米
        sortBuilder.order(SortOrder.ASC);//升序排列
        return sortBuilder;
    }
    /**
     * geo搜索 可以根据距离排序*/
    public static List<String> queryGeo(String indexName,double lat,double lon){
        //1.实例化 查询条件-全匹配
        MatchAllQueryBuilder builder=QueryBuilders.matchAllQuery();
        //2.实例化资源搜索对象
        SearchRequest request=initRequest(indexName,builder,getGeoSort(lat, lon));
        try {
            //3.执行搜索请求并获取搜索结果
            SearchResponse response=client.search(request,RequestOptions.DEFAULT);
            return getResult(response);
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 根据定位进行半径内的数据查询*/
    public static List<String> queryGeoCircle(String indexName,double lat,double lon,int length){
        //1.实例化 查询条件-全匹配
        GeoDistanceQueryBuilder builder=QueryBuilders.geoDistanceQuery("location");
        //2.设置geo查询的条件
        builder.point(lat, lon);//设置当前的定位的经纬度
        builder.distance(length,DistanceUnit.METERS);//设置半径，单位米
        //3.创建搜索请求对象
        SearchRequest request=initRequest(indexName,builder,getGeoSort(lat, lon));
        try {
            //4.执行搜索请求并获取搜索结果
            SearchResponse response=client.search(request,RequestOptions.DEFAULT);
            //5.获取搜索的结果对象
            return getResult(response);
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }
}
